home *** CD-ROM | disk | FTP | other *** search
/ Aminet 19 / Aminet 19 (1997)(GTI - Schatztruhe)[!][Jun 1997].iso / Aminet / text / misc / nroff.lha / nroff / macros.c < prev    next >
C/C++ Source or Header  |  1997-01-24  |  10KB  |  572 lines

  1. /*
  2.  *    macros.c - macro input/output processing for nroff word processor
  3.  *
  4.  *    adapted for atariST/TOS by Bill Rosenkranz 11/89
  5.  *    net:    rosenkra@hall.cray.com
  6.  *    CIS:    71460,17
  7.  *    GENIE:    W.ROSENKRANZ
  8.  *
  9.  *    original author:
  10.  *
  11.  *    Stephen L. Browning
  12.  *    5723 North Parker Avenue
  13.  *    Indianapolis, Indiana 46220
  14.  *
  15.  *    history:
  16.  *
  17.  *    - Originally written in BDS C;
  18.  *    - Adapted for standard C by W. N. Paul
  19.  *    - Heavily hacked up to conform to "real" nroff by Bill Rosenkranz
  20.  */
  21.  
  22. #undef NRO_MAIN                    /* extern globals */
  23.  
  24. #include <stdio.h>
  25. #include "nroff.h"
  26.  
  27.  
  28.  
  29. /*------------------------------*/
  30. /*    defmac            */
  31. /*------------------------------*/
  32. defmac (p, infp)
  33. register char  *p;
  34. FILE           *infp;
  35. {
  36.  
  37. /*
  38.  *    Define a macro. top level, read from stream.
  39.  *
  40.  *    we should read macro without interpretation EXCEPT:
  41.  *
  42.  *    1) number registers are interpolated
  43.  *    2) strings indicated by \* are interpolated
  44.  *    3) arguments indicated by \$ are interpolated
  45.  *    4) concealed newlines indicated by \(newline) are eliminated
  46.  *    5) comments indicated by \" are eliminated
  47.  *    6) \t and \a are interpreted as ASCII h tab and SOH.
  48.  *    7) \\ is interpreted as backslash and \. is interpreted as a period.
  49.  *
  50.  *    currently, we do only 3. a good place to do it would be here before
  51.  *    putmac, after colmac...
  52.  */
  53.  
  54.     register char  *q;
  55.     register int    i;
  56.     char        name[MNLEN];
  57.     char        defn[MXMLEN];
  58.     char        newend[10];
  59.  
  60.  
  61.     /*
  62.      *   skip the .de and get to the name...
  63.      */
  64.     q = skipwd (p);
  65.     q = skipbl (q);
  66.  
  67.     /*
  68.      *   ok, name now holds the name. make sure it is valid (i.e. first
  69.      *   char is alpha...). getwrd returns the length of the word.
  70.      */
  71.     i = getwrd (q, name);
  72.     if (!isprint (*name))
  73.     {
  74.         fprintf (err_stream,
  75.             "***%s: missing or illegal macro definition name\n",
  76.             myname);
  77.         err_exit (-1);
  78.     }
  79.  
  80.     /*
  81.      *   truncate to 2 char max name.
  82.      */
  83.     if (i > 2)
  84.         name[2] = EOS;
  85.  
  86.  
  87.     /*
  88.      *   skip the name and see if we have a new end defined...
  89.      */
  90.     q = skipwd (p);
  91.     q = skipbl (q);
  92.     for (i = 0; i < 10; i++)
  93.         newend[i] = EOS;
  94.  
  95.     for (i = 0; (i < 10) && ( isalpha (q[i]) || isdigit (q[i]) ); i++)
  96.     {
  97.         newend[i] = q[i];
  98.     }
  99.  
  100.  
  101.  
  102.     /*
  103.      *   read a line from input stream until we get the end of macro
  104.      *   command (.en or ..). actually. we should have read the next
  105.      *   field just above here to get the .de NA . or .de NA en string
  106.      *   to be new end of macro.
  107.      */
  108.     i = 0;
  109.     while (getlin (p, infp) != EOF)
  110.     {
  111.         if (p[0] == dc.cmdchr && p[1] == '\\' && p[2] == '\"')
  112.         {
  113.             /*
  114.              *   comment, ignore it
  115.              */
  116.             continue;
  117.         }
  118.         if (p[0] == dc.cmdchr && newend[0] != EOS
  119.         &&  p[1] == newend[0] && p[2] == newend[1])
  120.         {
  121.             /*
  122.              *   replacement end found
  123.              */
  124.             break;
  125.         }
  126.         if (p[0] == dc.cmdchr && p[1] == 'e' && p[2] == 'n')
  127.         {
  128.             /*
  129.              *   .en found
  130.              */
  131.             break;
  132.         }
  133.         if (p[0] == dc.cmdchr && p[1] == dc.cmdchr)
  134.         {
  135.             /*
  136.              *   .. found
  137.              */
  138.             break;
  139.         }
  140.  
  141.  
  142.         /*
  143.          *   collect macro from the line we just read. all this does
  144.          *   is put it in the string defn.
  145.          */
  146.         if ((i = colmac (p, defn, i)) == ERR)
  147.         {
  148.             fprintf (err_stream,
  149.                 "***%s: macro definition too long\n", myname);
  150.             err_exit (-1);
  151.         }
  152.     }
  153.  
  154.  
  155.     /*
  156.      *   store the macro
  157.      */
  158.     if (!ignoring)
  159.     {
  160.         if (putmac (name, defn) == ERR)
  161.         {
  162.             fprintf (err_stream,
  163.                 "***%s: macro definition table full\n", myname);
  164.             err_exit (-1);
  165.         }
  166.     }
  167. }
  168.  
  169.  
  170.  
  171.  
  172.  
  173. /*------------------------------*/
  174. /*    colmac            */
  175. /*------------------------------*/
  176. colmac (p, d, i)
  177. register char  *p;
  178. char           *d;
  179. register int    i;
  180. {
  181.  
  182. /*
  183.  *    Collect macro definition from input stream
  184.  */
  185.  
  186.     char   *pstart = p;
  187.     int    istart = i;
  188.  
  189.     while (*p != EOS)
  190.     {
  191.         /*
  192.          *   are we over the length limit for a single macro?
  193.          */
  194.         if (i >= MXMLEN - 1)
  195.         {
  196.             d[i - 1] = EOS;
  197.             return (ERR);
  198.         }
  199.  
  200.         /*
  201.          *   "i break for comments..."
  202.          */
  203.         if (*p == '\\' && *(p+1) == '\"')
  204.         {
  205.             /*
  206.              *   first back over any whitespace between comment
  207.              *   start and last character in line. remember to
  208.              *   decrement counter i, too...
  209.              */
  210.             p--;
  211.             while (isspace (*p) && p > pstart && i > istart)
  212.             {
  213.                 p--;
  214.                 i--;
  215.             }
  216.  
  217.             /*
  218.              *   now skip over the comment until we reach the
  219.              *   trailing newline
  220.              */
  221.             while (*p != EOS)
  222.             {
  223.                 if (*p == '\n' || *p == '\r')
  224.                     break;
  225.                 p++;
  226.             }
  227.         }
  228.  
  229.         /*
  230.          *   skip quoted things
  231.          */
  232.         if (*p == '\\' && *(p+1) == '\\')
  233.             p++;
  234.  
  235.         /*
  236.          *   copy it
  237.          */
  238.         d[i++] = *p++;
  239.     }
  240.     d[i] = EOS;
  241.     return (i);
  242. }
  243.  
  244.  
  245.  
  246.  
  247.  
  248. /*------------------------------*/
  249. /*    putmac            */
  250. /*------------------------------*/
  251. putmac (name, p)
  252. char   *name;
  253. char   *p;
  254. {
  255.  
  256. /*
  257.  *    Put macro definition into table
  258.  *
  259.  *    NOTE: any expansions of things like number registers SHOULD
  260.  *    have been done already.
  261.  */
  262.  
  263.  
  264.     /*
  265.      *   any room left? (did we exceed max number of possible macros)
  266.      */
  267.     if (mac.lastp >= MXMDEF)
  268.         return (ERR);
  269.  
  270.     /*
  271.      *   will new one fit in big buffer?
  272.      */
  273.     if (mac.emb + strlen (name) + strlen (p) + 1 > &mac.mb[MACBUF])
  274.     {
  275.         return (ERR);
  276.     }
  277.  
  278.  
  279.     /*
  280.      *   add it...
  281.      *
  282.      *   bump counter, set ptr to name, copy name, copy def.
  283.      *   finally increment end of macro buffer ptr (emb).
  284.      *
  285.      *   macro looks like this in mb:
  286.      *
  287.      *    mac.mb[MACBUF]        size of total buf
  288.      *    lastp < MXMDEF        number of macros possible
  289.      *    *mnames[MXMDEF]        -> names, each max length
  290.      *    ..._____________________________...____________________...
  291.      *        / / /|X|X|0|macro definition      |0| / / / / / / /
  292.      *    .../_/_/_|_|_|_|________________...___|_|/_/_/_/_/_/_/_...
  293.      *          ^
  294.      *          |
  295.      *          \----- mac.mnames[mac.lastp] points here
  296.      *
  297.      *   both the 2 char name (XX) and the descripton are null term and
  298.      *   follow one after the other.
  299.      */
  300.     ++mac.lastp;
  301.     mac.mnames[mac.lastp] = mac.emb;
  302.     strcpy (mac.emb, name);
  303.     strcpy (mac.emb + strlen (name) + 1, p);
  304.     mac.emb += strlen (name) + strlen (p) + 2;
  305.  
  306.     return (OK);
  307. }
  308.  
  309.  
  310.  
  311.  
  312.  
  313.  
  314. /*------------------------------*/
  315. /*    getmac            */
  316. /*------------------------------*/
  317. char   *getmac (name)
  318. register char  *name;
  319. {
  320.  
  321. /*
  322.  *    Get (lookup) macro definition from namespace
  323.  */
  324.  
  325.     register int    i;
  326.  
  327.     /*
  328.      *   loop for all macros, starting with last one
  329.      */
  330.     for (i = mac.lastp; i >= 0; --i)
  331.     {
  332.         /*
  333.          *   is this REALLY a macro?
  334.          */
  335.         if (mac.mnames[i])
  336.         {
  337.             /*
  338.              *   if it compares, return a ptr to it
  339.              */
  340.             if (!strcmp (name, mac.mnames[i]))
  341.             {
  342. /*!!!debug            puts (mac.mnames[i]);*/
  343.  
  344.                 if (mac.mnames[i][1] == EOS)
  345.                     return (mac.mnames[i] + 2);
  346.                 else
  347.                     return (mac.mnames[i] + 3);
  348.             }
  349.         }
  350.     }
  351.  
  352.     /*
  353.      *   none found, return null
  354.      */
  355.     return (NULL_CPTR);
  356. }
  357.  
  358.  
  359.  
  360.  
  361.  
  362.  
  363. /*------------------------------*/
  364. /*    maceval            */
  365. /*------------------------------*/
  366. maceval (p, m)
  367. register char  *p;
  368. char           *m;
  369. {
  370.  
  371. /*
  372.  *    Evaluate macro expansion
  373.  */
  374.  
  375.     register int    i;
  376.     register int    j;
  377.     char           *argp[15];
  378.     char        c;
  379.     int        xc;
  380.  
  381.  
  382.  
  383.     /*
  384.      *   replace command char with EOS
  385.      */
  386.     *p++ = EOS;
  387.  
  388.  
  389.     /* 
  390.      *   initialize argp array to substitute command
  391.      *   string for any undefined argument
  392.      *
  393.      *    NO!!! this is fixed...
  394.      */
  395. /*    for (i = 0; i < 10; ++i)
  396.         argp[i] = p;
  397. */
  398.     /*
  399.      *   skip the command name
  400.      */
  401.     p = skipwd (p);
  402.     *p++ = EOS;
  403.  
  404.  
  405.     /*
  406.      *   loop for all $n variables...
  407.      */
  408.     for (i = 0; i < 10; ++i)
  409.     {
  410.         /*
  411.          *   get to substituted param and if no more, reset remaining
  412.          *   args to NULL and stop. using "i" here IS ok...
  413.          */
  414.         p = skipbl (p);
  415.         if (*p == '\r' || *p == '\n' || *p == EOS)
  416.         {
  417.             if (debugging)
  418.                 fprintf (err_stream,
  419.                 "***%s.maceval: set_ireg(.$, %d, 0)\n",
  420.                 myname,i);
  421.  
  422.             set_ireg (".$", i, 0);
  423.             for ( ; i < 10; i++)
  424.             {
  425.                 argp[i] = NULL_CPTR;
  426.             }
  427.             break;
  428.         }
  429.  
  430.  
  431.         /*
  432.          *   ...otherwise, see if this param is quoted. if it is,
  433.          *   it is all one parameter, even with blanks (but not
  434.          *   newlines...). look for another "c" (which is the quote).
  435.          *
  436.          *   if no quote, just read the arg as a single word and null
  437.          *   terminate it.
  438.          */
  439.         if (*p == '\'' || *p == '"')
  440.         {
  441.             c = *p++;
  442.             argp[i] = p;
  443.             while (*p != c && *p != '\r' && *p != '\n' && *p != EOS)
  444.                 ++p;
  445.             *p++ = EOS;
  446.         }
  447.         else
  448.         {
  449.             argp[i] = p;
  450.             p = skipwd (p);
  451.             *p++ = EOS;
  452.         }
  453.     }
  454.  
  455.  
  456.     /*
  457.      *   m contains text of the macro. p contained the input line.
  458.      *   here we start at the end of the macro def and see if there
  459.      *   are any $n thingies. go backwards.
  460.      */
  461.     for (i = strlen (m) - 1; i >= 0; --i)
  462.     {
  463.         /*
  464.          *   found a $.
  465.          */
  466.         if (i > 0 && m[i - 1] == '$')
  467.         {
  468.             if (!isdigit (m[i]))
  469.             {
  470.                 /*
  471.                  *   it wasn't a numeric replacement arg so
  472.                  *   push this char back onto input stream
  473.                  */
  474.                 putbak (m[i]);
  475.             }
  476.             else
  477.             {
  478.                 /*
  479.                  *   it WAS a numeric replacement arg. so we
  480.                  *   want to push back the appropriate macro
  481.                  *   invocation arg. m[i]-'0' is the numerical
  482.                  *   value of the $1 thru $9. if the arg is
  483.                  *   not there, argp[n] will be (char *) 0
  484.                  *   and pbstr will do nothing.
  485.                  */
  486.                 xc = m[i] - '1';
  487.                 if (argp[xc])
  488.                     pbstr (argp[xc]);
  489.                 --i;
  490.             }
  491.         }
  492.         else
  493.         {
  494.             /*
  495.              *   no $ so push back the char...
  496.              */
  497.             putbak (m[i]);
  498.         }
  499.     }
  500.  
  501.     /*
  502.      *   at this point, the iobuf will hold the new macro command, full
  503.      *   expanded for $n things. the return gets us right back to the
  504.      *   main loop in main() and we parse the (new) command just as if
  505.      *   it were read from a file.
  506.      */
  507.  
  508. }
  509.  
  510.  
  511.  
  512.  
  513.  
  514. /*------------------------------*/
  515. /*    printmac        */
  516. /*------------------------------*/
  517. printmac (opt)
  518. int    opt;                /* 0=name&size,1=total size,2=full */
  519. {
  520.  
  521. /*
  522.  *    print all macros and strings and tabulate sizes
  523.  */
  524.  
  525.     register int    i;        /* was long, minix needs int */
  526.     register long    space;
  527.      register long    totalspace;
  528.     register char  *pname;
  529.     register char  *pdef;
  530.  
  531.  
  532.     space      = 0L;
  533.     totalspace = 0L;
  534.  
  535.     fflush (out_stream);
  536.     fflush (err_stream);
  537.  
  538.     for (i = mac.lastp; i >= 0; --i)
  539.     {
  540.          /*
  541.          *   is this REALLY a macro?
  542.          */
  543.         if (mac.mnames[i])
  544.         {
  545.             pname = (char *) (mac.mnames[i]);
  546.             pdef  = pname + 3;
  547.             if (*(pname + 1) == '\0')
  548.                 pdef = pname + 2;
  549.  
  550.             space       = (long) strlen (pdef);
  551.             totalspace += space;
  552.  
  553.             switch (opt)
  554.             {
  555.             case 0:
  556.                 fprintf (err_stream, "%s %ld\n", pname, space);
  557.                 break;
  558.             case 2:
  559.                 fprintf (err_stream, "%s %ld\n", pname, space);
  560.                 fprintf (err_stream, "%s\n", pdef);
  561.                 break;
  562.             case 1:
  563.             default:
  564.                 break;
  565.             }
  566.         }
  567.     }
  568.     fprintf (err_stream, "Total space: %ld\n", totalspace);
  569.     
  570. }
  571.  
  572.